﻿#include "stdafx.h"
#if _QG_ENABLE_WIDGET
#include "qg/qgasv.h"
#include "qg/qgmtrl.h"
#include "qg/qgrdraw.h"
#include "qg/qgwidget.h"

//////////////////////////////////////////////////////////////////////////
// 위젯

namespace _widget
{
	qgWidgetResource DummyResource =
	{
		tpl::ColorValue(0xFFFFFFFF),
		tpl::Quad(0.0f, 0.0f, 0.0f, 0.0f),
		false
	};
}


//////////////////////////////////////////////////////////////////////////
// 컨트롤
KIMPL_SUBCLASS_ABSTRACT(qwControl, "WidgetControl");

qwControl::qwControl(qgWidgetType type, kint instmask)
: _widget(type)
, _bound(0, 0, 50, 50)
, _status(QGWS_NORMAL)
, _insts(instmask | QGWI_ENABLE | QGWI_VISIBLE)
, _refresh(true)
, _color_shadow(30, 30, 30, 128)
, _color_border(255, 255, 255)
{
	_textinfo.size = 16;
	_textinfo.align = QGWALIGN_CENTER | QGWALIGN_VCENTER;
	_textinfo.color.Set(255, 255, 255);
	_textinfo.anch.Set(0, 0);

	// OnInitialize 참조
}

qwControl::~qwControl()
{
	kobj_unload(_tex);
	kobj_unload(_font);
}

const qgWidgetResource& qwControl::GetResource()
{
	return _res[_status];
}

const qgWidgetResource& qwControl::GetResource(qgWidgetElement nth)
{
	return nth >= QGWELM_NORMAL && nth <= QGWELM_DISABLE
		? _res[nth] : _widget::DummyResource;
}

bool qwControl::SetResource(qgWidgetElement nth, const qgWidgetResource& res)
{
	k_return_value_if_fail((ksize_t)nth < (ksize_t)QGWS_MAX_VALUE, false);

	_res[nth] = res;

	return true;
}

kint qwControl::GetInsts(kint mask /*= 0*/)
{
	return K_OMASK(_insts, mask);
}

bool qwControl::IsVisible()
{
	return K_OFLAG(_insts, QGWI_VISIBLE);
}

bool qwControl::IsEnable()
{
	return K_OFLAG(_insts, QGWI_ENABLE);
}

bool qwControl::IsContainer()
{
	return K_OFLAG(_insts, QGWI_CTNR);
}

bool qwControl::IsRibbon()
{
	return K_OFLAG(_insts, QGWI_RIBBON);
}

bool qwControl::IsAccept()
{
	return K_OFLAG(_insts, QGWI_ACCEPT);
}

bool qwControl::IsCancel()
{
	return K_OFLAG(_insts, QGWI_CANCEL);
}

bool qwControl::CanFill()
{
	return K_OFLAG(_insts, QGWI_FILL);
}

bool qwControl::CanInput()
{
	return K_OFLAG(_insts, QGWI_INPUT);
}

bool qwControl::CanSize()
{
	return K_OFLAG(_insts, QGWI_SIZABLE);
}

bool qwControl::CanMove()
{
	return K_OFLAG(_insts, QGWI_MOVABLE);
}

bool qwControl::HasAnchor()
{
	return K_OFLAG(_insts, QGWI_ANCHOR);
}

bool qwControl::HasShadow()
{
	return K_OFLAG(_insts, QGWI_SHADOW);
}

bool qwControl::HasBorder()
{
	return K_OFLAG(_insts, QGWI_BORDER);
}

bool qwControl::HasSunken()
{
	return K_OFLAG(_insts, QGWI_SUNKEN);
}

bool qwControl::HasExtInfo()
{
	return K_OFLAG(_insts, QGWI_EXTINFO);
}

bool qwControl::HasText()
{
	return _textstr.IsHave();
}

bool qwControl::ReadOnly()
{
	return K_OFLAG(_insts, QGWI_READONLY);
}

const tpl::String& qwControl::GetText()
{
	return _textstr;
}

const char* qwControl::GetTextData()
{
	return _textstr.Data();
}

kint qwControl::GetTextLength()
{
	return _textstr.Length();
}

void qwControl::SetVisible(bool value)
{
	K_UFLAG(&_insts, QGWI_VISIBLE, value);
}

void qwControl::SetEnable(bool value)
{
	K_UFLAG(&_insts, QGWI_ENABLE, value);
}

void qwControl::SetFillMode(bool isfill)
{
	K_UFLAG(&_insts, QGWI_FILL, isfill);
}

void qwControl::SetAcceptMode(bool value)
{
	K_UFLAG(&_insts, QGWI_ACCEPT, value);
}

void qwControl::SetCancelMode(bool value)
{
	K_UFLAG(&_insts, QGWI_CANCEL, value);
}

void qwControl::SetInputMode(bool isinput)
{
	K_UFLAG(&_insts, QGWI_INPUT, isinput);
}

void qwControl::SetSizeMode(bool isenable)
{
	K_UFLAG(&_insts, QGWI_SIZABLE, isenable);
}

void qwControl::SetMoveMode(bool isenable)
{
	K_UFLAG(&_insts, QGWI_MOVABLE, isenable);
}

void qwControl::SetShadowMode(bool isenable)
{
	K_UFLAG(&_insts, QGWI_SHADOW, isenable);
}

void qwControl::SetBorderMode(bool isenable)
{
	K_UFLAG(&_insts, QGWI_BORDER, isenable);
}

void qwControl::SetSunkenMode(bool isenable)
{
	K_UFLAG(&_insts, QGWI_SUNKEN, isenable);
}

void qwControl::SetExtInfo(bool isenable)
{
	K_UFLAG(&_insts, QGWI_EXTINFO, isenable);
}

void qwControl::SetReadOnly(bool readonly)
{
	K_UFLAG(&_insts, QGWI_READONLY, readonly);
}

void qwControl::SetTexture(qgTexture* tex)
{
	if (_tex != tex)
	{
		kobj_unload(_tex);
		_tex = tex;
		kobj_load(tex);
	}
}

void qwControl::OpenTexture(const char* filename)
{
	kobj_unload(_tex);
	_tex = _shed->GetDevice()->CreateTexture(filename, QGTEXF_S2D);
}

void qwControl::SetTextSize(kint size)
{
	_textinfo.size = size;
	SetRefresh();
}

void qwControl::SetTextAlign(kint align)
{
	_textinfo.align = align;
	SetRefresh();
}

void qwControl::SetTextColor(const tpl::ColorValue& color)
{
	_textinfo.color = color;
	SetRefresh();
}

bool qwControl::ReplaceColor(qgWidgetElement nth, const tpl::ColorValue& value)
{
	qgWidgetResource res = GetResource(nth);
	res.color = value;
	return SetResource(nth, res);
}

void qwControl::SetBound(const tpl::Rect& bound)
{
	_bound = bound;
	SetRefresh();
}

void qwControl::SetBound(kint x, kint y, kint w, kint h)
{
	_bound.SetSize(x, y, w, h);
	SetRefresh();
}

void qwControl::SetLocation(kint x, kint y)
{
	_bound.Move(x, y);
	SetRefresh();
}

void qwControl::SetSize(kint w, kint h)
{
	_bound.Expand(w, h);
	SetRefresh();
}

void qwControl::SetStatus(qgWidgetStatus status)
{
	OnChangeStatus(status);
	_status = status;
}

void qwControl::SetParent(qwControl* parent)
{
	OnChangeParent(parent);
	_parent = parent;
}

void qwControl::SetShed(qgWidgetShed* shed)
{
	_shed = shed; 
}

void qwControl::SetFont(qgFont* font)
{
	if (font && _font != font)
	{
		OnChangeFont(font);

		kobj_unload(_font);
		_font = font;
		font->Load();

		SetRefresh();
	}
}

void qwControl::SetText(const char* str)
{
	_textstr = str;
	OnTextChanged(_textstr.Data(), _textstr.Length());
	SetRefresh();
}

void qwControl::SetTextL(const kwchar* uni)
{
#if _SB_WINDOWS_
	ksize_t n = k_conv_utf16_to_utf8(NULL, 0, uni, 0) + 1;
	char* psz = (char*)alloca(n*sizeof(kwchar));
	k_conv_utf16_to_utf8(psz, n, uni, 0);
#else
	ksize_t n = k_conv_ucs4_to_utf8(NULL, 0, uni, 0) + 1;
	char* psz = (char*)alloca(n*sizeof(kwchar));
	k_conv_ucs4_to_utf8(psz, n, uni, 0);
#endif

	SetText(psz);
}

void qwControl::BuildBound(bool clip)
{
	const tpl::Rect& offset = _parent ? _parent->GetClient() : _shed->GetBound();

	_client = _bound.Offset(offset.left, offset.top);

	if (clip)
	{
		// 클립을 하지 않을 경우
		// combo가 form/panel의 쫄따구 일 때 열리면 부모 영역을 넘어감. 클립하면 안됨
		if (_client.right > offset.right)
			_client.right = offset.right;

		if (_client.bottom > offset.bottom)
			_client.bottom = offset.bottom;
	}
}

tpl::Rect qwControl::CalcBound(const tpl::Rect& bound)
{
	const tpl::Rect& offset = _parent ? _parent->GetClient() : _shed->GetBound();

	return bound.Offset(offset.left, offset.top);
}

tpl::Point qwControl::CalcAlign(const tpl::Point& size)
{
	return CalcAlign(_textinfo.align, size, _client);
}

tpl::Point qwControl::CalcAlign(kint align, const tpl::Point& size, const tpl::Rect& bound)
{
	kint w = bound.Width();
	kint h = bound.Height();

	return tpl::Point(
		(align&QGWALIGN_RIGHT) ? w - size.x : (align&QGWALIGN_CENTER) ? (w - size.x) / 2 : 0,
		(align&QGWALIGN_BOTTOM) ? h - size.y : (align&QGWALIGN_VCENTER) ? (h - size.y) / 2 : 0);
}

bool qwControl::TestPick(kint x, kint y, bool isclient)
{
	if (_parent && isclient)
	{
		const tpl::Rect& offset = _parent->GetClient();
		x -= offset.left;
		y -= offset.top;
	}
	else
	{
#if 0
		const tpl::Rect& offset = _client;
		x -= offset.left;
		y -= offset.top;
#endif
	}

	return _bound.OnPoint(x, y);
}

void qwControl::BuildTextAnch()
{
	_font->SetSize(_textinfo.size);
	_textinfo.anch = CalcAlign(_font->CalcSize(0, _textstr.Data()));
}

void qwControl::OnInitialize()
{
	_res[QGWS_NORMAL] = _shed->GetResource(QGWELM_NORMAL);
	_res[QGWS_SELECT] = _shed->GetResource(QGWELM_SELECT);
	_res[QGWS_OVER] = _shed->GetResource(QGWELM_OVER);
	_res[QGWS_DISABLE] = _shed->GetResource(QGWELM_DISABLE);
}

bool qwControl::OnUpdate(float adv)
{
	if (NeedRefresh())
		SetRefresh(false);

	return true;
}

void qwControl::OnDraw()
{
#if 0
	if (CanFill())
		_shed->DrawFillRect(_tex, _client, GetColor(), GetCoord());
#endif

	if (_ecb_draw)
		_ecb_draw(this, _client);
}

#endif
